package persistencia;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Example;

public abstract class GenericDAOAbstract<T, ID extends Serializable> implements
		GenericDAO<T, ID> {

	private Class<T> persistentClass;
	private Session session;

	@SuppressWarnings("unchecked")
	public GenericDAOAbstract() {
		this.persistentClass = (Class<T>)
				( (ParameterizedType) getClass().getGenericSuperclass() )
				.getActualTypeArguments()[0];
	}
	
	public void setSession(Session session){
		this.session = session;
	}
	
	public Session getSession(){
		if (session == null){
			session = HibernateUtil.getSessionFactory().openSession();
		}	
		return session;
	}
	
	public Class<T> getPersistentClass(){
		return persistentClass;
	}
	
	public void save(T entity) throws DAOException {
		getSession().saveOrUpdate(entity);
	}
	
	public void update(T entity)throws DAOException {
		getSession().update(entity);
	}
	
	public void delete(T entity) throws DAOException {
		getSession().delete(entity);
	}
	
	public void flush() throws DAOException {
		getSession().flush();
	}

	public void clear() throws DAOException {
		getSession().clear();
		
	}
	
	@SuppressWarnings({ "deprecation", "unchecked" })
	public T findByID(ID id, boolean lock) throws DAOException {
		T entity;
		if (lock){
			entity = (T) getSession().load(getPersistentClass(), id, LockMode.UPGRADE);
		} else {
			entity = (T) getSession().load(getPersistentClass(), id);
		}
		return entity;
	}
	
	@SuppressWarnings("unchecked")
	public List<T> findByExample(T exampleInstance, String... excludeProperty) throws DAOException {
		Criteria criteria = getSession().createCriteria(getPersistentClass());
		Example example = Example.create(exampleInstance);
		for (String exclude : excludeProperty) {
			example.excludeProperty(exclude);
		}
		criteria.add(example);
		return criteria.list();
	}
	
	public List<T> findAll() throws DAOException {
		return findByCriteria();
	}

	@SuppressWarnings("unchecked")
	protected List<T> findByCriteria(Criterion... criterion) {
		Criteria criteria = getSession().createCriteria(getPersistentClass());
		for (Criterion c : criterion) {
			criteria.add(c);
		}
		return criteria.list();
	}
	
}
